#include "download_file_command.h"
#include "service/backend_service.h"
#include "../database/database_manager.h"
#include "../database/file_system_status.h"
#include "command_executor.h"
#include <QDebug>
#include <QUrl>
#include <QNetworkRequest>
#include <QStandardPaths>
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QDateTime>
#include <QRandomGenerator>
#include <QSettings>

DownloadFileCommand::DownloadFileCommand(QObject *parent)
    : BaseCommand(parent)
    , m_pendingUrl("")
    , m_pendingFileName("")
    , m_pendingFileId("")
{
}

DownloadFileCommand::~DownloadFileCommand()
{
}

void DownloadFileCommand::setNetworkAccessManager(QNetworkAccessManager *networkManager)
{
    // 如果之前已经设置了 networkManager，先断开旧的连接
    if (m_networkManager) {
        disconnect(m_networkManager, &QNetworkAccessManager::finished,
                   this, &DownloadFileCommand::handleDownloadFileResponse);
    }
    
    BaseCommand::setNetworkAccessManager(networkManager);
    
    // 连接网络请求完成信号
    if (m_networkManager) {
        connect(m_networkManager, &QNetworkAccessManager::finished,
                this, &DownloadFileCommand::handleDownloadFileResponse);
    }
}

bool DownloadFileCommand::execute(const QString &url, const QString &fileName, const QString &fileId)
{
    if (!isValid()) {
        qDebug() << "DownloadFileCommand: BackendService 或 QNetworkAccessManager 未设置";
        emit downloadFileCompleted(-1, "BackendService 或 QNetworkAccessManager 未设置", "");
        return false;
    }
    
    // 验证文件ID
    if (fileId.isEmpty()) {
        qDebug() << "DownloadFileCommand: 文件ID为空，无法下载文件";
        emit downloadFileCompleted(-1, "文件ID为空，无法下载文件", "");
        return false;
    }
    
    // 检查是否有accessToken，如果没有则先获取
    if (!ensureAccessToken()) {
        // 如果没有选中的公司ID，无法获取accessToken
        if (!m_backendService || m_backendService->loadSelectedCompanyId().isEmpty()) {
            qDebug() << "DownloadFileCommand: 没有选中的公司ID，无法获取accessToken";
            emit downloadFileCompleted(-1, "没有选中的公司ID，无法获取accessToken", "");
            return false;
        }
        // 正在获取 token，保存待处理的参数
        m_pendingUrl = url;
        m_pendingFileName = fileName;
        m_pendingFileId = fileId;
        return true; // 返回true表示已发起获取token的请求
    }
    
    // 获取 accessToken
    QString accessToken = CommandExecutor::getAccessToken();
    
    // 获取 baseUrl
    QString baseUrl = getBaseUrl();
    
    // 构建请求URL
    QString downloadUrl = buildRequestUrl(baseUrl, fileId);
    
    qDebug() << "DownloadFileCommand: 开始下载文件，URL:" << downloadUrl << "文件ID:" << fileId;
    
    // 创建网络请求
    QNetworkRequest request = createRequest(downloadUrl, "GET", "DownloadFileCommand/1.0");
    
    // 添加token到请求头
    addTokenToRequest(request, accessToken);
    
    // 发送GET请求
    QNetworkReply *reply = m_networkManager->get(request);
    qDebug() << "DownloadFileCommand: 发送下载文件请求，reply对象:" << reply;
    
    // 设置用户数据，用于识别请求类型
    reply->setProperty("requestType", "downloadFile");
    
    // 保存相对URL（用于构建本地保存目录结构）
    reply->setProperty("fileRelativeUrl", url);
    
    // 如果提供了文件名，保存到reply属性中
    if (!fileName.isEmpty()) {
        reply->setProperty("fileName", fileName);
    }
    
    // 如果提供了文件ID，保存到reply属性中（用于从数据库获取文件夹路径）
    if (!fileId.isEmpty()) {
        reply->setProperty("fileId", fileId);
    }
    
    // 连接下载进度信号
    connect(reply, &QNetworkReply::downloadProgress, this, [this](qint64 bytesReceived, qint64 bytesTotal) {
        emit downloadProgress(bytesReceived, bytesTotal);
    });
    
    return true;
}

void DownloadFileCommand::handleDownloadFileResponse(QNetworkReply *reply)
{
    // 检查对象是否仍然有效（可能在信号排队期间被销毁）
    if (!isValid()) {
        qDebug() << "DownloadFileCommand: 对象已被销毁，忽略响应";
        if (reply) {
            reply->deleteLater();
        }
        return;
    }
    
    if (!reply) {
        qDebug() << "DownloadFileCommand: 下载文件响应为空";
        if (isValid()) {
            emit downloadFileCompleted(-1, "下载响应为空", "");
        }
        return;
    }
    
    QString requestType = reply->property("requestType").toString();
    if (requestType != "downloadFile") {
        // 不是下载文件请求，忽略
        reply->deleteLater();
        return;
    }
    
    qDebug() << "DownloadFileCommand: 处理下载文件响应，错误:" << reply->error();
    
    // 再次检查对象是否仍然有效
    if (!isValid()) {
        qDebug() << "DownloadFileCommand: 对象已被销毁，忽略响应";
        reply->deleteLater();
        return;
    }
    
    if (reply->error() == QNetworkReply::NoError) {
        // 下载成功，保存文件
        QByteArray data = reply->readAll();
        qDebug() << "DownloadFileCommand: 下载文件成功，数据大小:" << data.size() << "字节";
        
        // 获取当前用户名（从 BackendService 获取）
        // 注意：这里需要通过 BackendService 获取用户名，但 BackendService 没有公开方法
        // 我们需要通过其他方式获取，或者从数据库获取
        // 暂时使用一个辅助方法，或者从设置中获取
        QString currentUsername;
        QString homePath = QStandardPaths::writableLocation(QStandardPaths::HomeLocation);
        if (!homePath.isEmpty()) {
            QString settingsPath = QDir(homePath).filePath(".myapps/setting.ini");
            if (QFile::exists(settingsPath)) {
                QSettings settings(settingsPath, QSettings::IniFormat);
                currentUsername = settings.value("Login/Username", "").toString();
            }
        }
        
        // 构建用户工作目录: Home/.myapps/{username}/work
        QString workBase = QDir::cleanPath(homePath + "/.myapps/" + currentUsername + "/work");
        QString tempBase = QDir::cleanPath(homePath + "/.myapps/" + currentUsername + "/tmp");
        
        QString targetPath;
        QString fileId = reply->property("fileId").toString();
        
        // 如果提供了文件ID，从数据库获取文件夹路径和文件名
        if (!fileId.isEmpty() && m_databaseManager) {
            // 查询文件信息
            KmsFile kmsFile = m_databaseManager->queryFileById(fileId);
            if (!kmsFile.id.isEmpty()) {
                QString fileName = kmsFile.name;
                QString folderId = kmsFile.folderId;
                
                // 查询文件夹信息获取路径
                QString folderPath = "";
                if (!folderId.isEmpty()) {
                    KmsFolder folder = m_databaseManager->queryFolderById(folderId);
                    if (!folder.id.isEmpty()) {
                        folderPath = folder.path;
                    }
                }
                
                // 构建目标路径: workBase + folderPath + fileName
                if (!folderPath.isEmpty()) {
                    // 清理路径：移除开头的斜杠
                    if (folderPath.startsWith('/')) {
                        folderPath.remove(0, 1);
                    }
                    targetPath = QDir::cleanPath(workBase + "/" + folderPath + "/" + fileName);
                } else {
                    // 如果没有文件夹路径，只使用文件名
                    targetPath = QDir::cleanPath(workBase + "/" + fileName);
                }
                
                qDebug() << "DownloadFileCommand: 使用数据库路径，文件夹路径:" << folderPath << "文件名:" << fileName;
            }
        }
        
        // 如果无法从数据库获取路径，则使用原有的相对URL方式
        if (targetPath.isEmpty()) {
            // 使用相对URL作为目录结构（包含文件名）
            QString relativeUrl = reply->property("fileRelativeUrl").toString();
            if (relativeUrl.startsWith('/')) {
                relativeUrl.remove(0, 1);
            }
            
            // 如果未提供相对URL，则回退到从实际请求URL解析文件名
            if (relativeUrl.isEmpty()) {
                QString fileName = reply->property("fileName").toString();
                if (fileName.isEmpty()) {
                    QUrl reqUrl = reply->url();
                    fileName = QFileInfo(reqUrl.path()).fileName();
                    if (fileName.isEmpty()) {
                        fileName = "downloaded_file";
                    }
                }
                relativeUrl = fileName;
            }
            
            targetPath = QDir::cleanPath(workBase + "/" + relativeUrl);
            qDebug() << "DownloadFileCommand: 使用相对URL路径:" << relativeUrl;
        }
        
        // 先保存到临时目录
        QString tmpDir = QDir::cleanPath(tempBase);
        if (!QDir().mkpath(tmpDir)) {
            qDebug() << "DownloadFileCommand: 创建临时目录失败:" << tmpDir;
            emit downloadFileCompleted(-2, "无法创建临时目录: " + tmpDir, "");
            reply->deleteLater();
            return;
        }
        
        // 生成临时文件名（使用文件ID或随机名称）
        QString tmpFileName;
        if (!fileId.isEmpty()) {
            tmpFileName = fileId + ".tmp";
        } else {
            tmpFileName = QString("download_%1_%2.tmp")
                             .arg(QDateTime::currentMSecsSinceEpoch())
                             .arg(QRandomGenerator::global()->bounded(100000));
        }
        QString tmpFilePath = QDir::cleanPath(tmpDir + "/" + tmpFileName);
        
        // 保存文件到临时目录
        QFile tmpFile(tmpFilePath);
        if (!tmpFile.open(QIODevice::WriteOnly)) {
            qDebug() << "DownloadFileCommand: 无法创建临时文件:" << tmpFilePath << "错误:" << tmpFile.errorString();
            emit downloadFileCompleted(-2, "无法创建临时文件: " + tmpFile.errorString(), "");
            reply->deleteLater();
            return;
        }
        
        qint64 bytesWritten = tmpFile.write(data);
        tmpFile.close();
        
        if (bytesWritten != data.size()) {
            qDebug() << "DownloadFileCommand: 文件写入失败，写入字节数不匹配，期望:" << data.size() << "实际:" << bytesWritten;
            // 删除临时文件
            tmpFile.remove();
            emit downloadFileCompleted(-3, "文件保存失败，写入字节数不匹配", "");
            reply->deleteLater();
            return;
        }
        
        qDebug() << "DownloadFileCommand: 文件已保存到临时目录:" << tmpFilePath;
        
        // 确保目标目录存在
        QFileInfo targetInfo(targetPath);
        if (!QDir().mkpath(targetInfo.path())) {
            qDebug() << "DownloadFileCommand: 创建目标目录失败:" << targetInfo.path();
            // 删除临时文件
            tmpFile.remove();
            emit downloadFileCompleted(-2, "无法创建目录: " + targetInfo.path(), "");
            reply->deleteLater();
            return;
        }
        
        // 如果目标文件已存在，先删除（确保移动操作成功）
        if (QFile::exists(targetPath)) {
            if (!QFile::remove(targetPath)) {
                qDebug() << "DownloadFileCommand: 无法删除已存在的目标文件:" << targetPath;
                // 删除临时文件
                tmpFile.remove();
                emit downloadFileCompleted(-2, "无法删除已存在的目标文件", "");
                reply->deleteLater();
                return;
            }
        }
        
        // 从临时目录移动到最终位置
        if (!QFile::rename(tmpFilePath, targetPath)) {
            qDebug() << "DownloadFileCommand: 移动文件失败，从:" << tmpFilePath << "到:" << targetPath;
            // 删除临时文件
            tmpFile.remove();
            emit downloadFileCompleted(-2, "无法移动文件到目标位置", "");
            reply->deleteLater();
            return;
        }
        
        qDebug() << "DownloadFileCommand: 文件移动成功，最终路径:" << targetPath;
        
        // 计算相对于工作目录的路径并更新到数据库
        if (!fileId.isEmpty() && m_databaseManager) {
            QDir workDir(workBase);
            QString relativePath = workDir.relativeFilePath(targetPath);
            // 将路径分隔符统一为正斜杠（用于跨平台兼容）
            relativePath = relativePath.replace('\\', '/');
            
            // 更新本地文件信息（包括相对路径）
            // 注意：不在此处计算校验和，校验和计算由文件系统监视器处理
            QFileInfo fileInfo(targetPath);
            qint64 fileSize = fileInfo.size();
            
            // 更新本地文件信息（不包括校验和，校验和由文件系统监视器计算）
            m_databaseManager->updateLocalFileInfo(fileId, fileSize, QString(), relativePath);
            
            // 更新文件状态为已同步 屏蔽此行，因为文件系统监视器会检测到文件变化，计算校验和并更新状态
            // m_databaseManager->updateFileStatus(fileId, FileSystemStatus::SYNCED);
            
            qDebug() << "DownloadFileCommand: 已更新数据库，文件ID:" << fileId << "相对路径:" << relativePath << "状态已更新为已同步，校验和将由文件系统监视器计算";
        }
        
        emit downloadFileCompleted(0, "文件下载成功", targetPath);
    } else {
        qDebug() << "DownloadFileCommand: 下载文件失败:" << reply->errorString();
        emit downloadFileCompleted(reply->error(), "下载失败: " + reply->errorString(), "");
    }
    
    reply->deleteLater();
}

QString DownloadFileCommand::buildRequestUrl(const QString &baseUrl, const QString &fileId)
{
    return baseUrl + QString("/kms/api/kms/download/%1").arg(fileId);
}

